home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-02-11 | 45.5 KB | 1,678 lines |
- /*
- * File: fmisc.r
- * Contents:
- * args, char, collect, copy, display, iand, icom, image, ior, ishift,
- * ixor, ord, name, runerr, seq, sort, sortf, type, variable
- */
-
- "args(p) - produce number of arguments for procedure p."
-
- function{1} args(x)
-
- if !is:procedure(x) then
- runerr(106, x)
-
- abstract {
- return integer
- }
- inline {
- return C_integer ((struct b_proc *)BlkLoc(x))->nparam;
- }
- end
-
- #if !COMPILER
- #ifdef ExternalFunctions
- #ifdef IconCalling
- /*
- * callout - call a C routine with an argument count and a list of descriptors.
- * #%#%
- */
- function{1} callout(x[nargs])
- body {
- dptr retval;
- struct pf_marker *newpfp;
- register word *newsp = sp;
- int signal;
-
- /*
- * Build a procedure frame. This is not normal for "built-in" procedures,
- * but we're preparing to call Icon back, if necessary. To get rid of
- * this frame, on the way out signal a Pret. The code between the dashed
- * lines is copied largely from invoke().
- */
- newpfp = (struct pf_marker *)(newsp + 1);
- newpfp->pf_nargs = nargs;
- newpfp->pf_argp = argp;
- newpfp->pf_pfp = pfp;
- newpfp->pf_ilevel = ilevel;
- newpfp->pf_scan = NULL;
-
- newpfp->pf_ipc = ipc;
- newpfp->pf_gfp = gfp;
- newpfp->pf_efp = efp;
-
- argp = cargp; /* cargp is newargp in invoke() */
- pfp = newpfp;
- newsp += Vwsizeof(*pfp);
-
- efp = 0;
- gfp = 0;
-
- sp = newsp;
- /*------------------------------------------------------------------------*/
-
- /*
- * Little cheat here. Although this is a var-arg procedure, we need
- * at least one argument to get started: pretend there is a null on
- * the stack. NOTE: Actually, at present, varargs functions always
- * have at least one argument, so this doesn't plug the hole.
- */
- if (nargs < 1)
- runerr(103, nulldesc);
-
- /*
- * Call the 'C routine caller' with a pointer to an array of descriptors.
- * Note that these are being left on the stack. We are passing
- * the name of the routine as part of the convention of calling
- * routines with an argc/argv technique.
- */
- signal = -1; /* presume successful completion */
- retval = extcall(x, nargs, &signal);
- if (signal >= 0) {
- if (retval == NULL)
- runerr(signal);
- else
- runerr(signal, retval);
- }
- if (retval != NULL) {
- Arg0 = *retval;
- return A_Pret_uw;
- }
- else
- return A_Pfail_uw;
- }
- end
-
- #else /* IconCalling */
-
- /*
- * callout - call a C library routine (or any C routine which doesn't call Icon)
- * with an argument count and a list of descriptors. This routine
- * doesn't build a procedure frame to prepare for calling Icon back.
- */
- function{1} callout(x[nargs])
- body {
- dptr retval;
- int signal;
-
- /*
- * Little cheat here. Although this is a var-arg procedure, we need
- * at least one argument to get started: pretend there is a null on
- * the stack. NOTE: Actually, at present, varargs functions always
- * have at least one argument, so this doesn't plug the hole.
- */
- if (nargs < 1)
- runerr(103, nulldesc);
-
- /*
- * Call the 'C routine caller' with a pointer to an array of descriptors.
- * Note that these are being left on the stack. We are passing
- * the name of the routine as part of the convention of calling
- * routines with an argc/argv technique.
- */
- signal = -1; /* presume successful completiong */
- retval = extcall(x, nargs, &signal);
- if (signal >= 0) {
- if (retval == NULL)
- runerr(signal);
- else
- runerr(signal, *retval);
- }
- if (retval != NULL) {
- return *retval;
- }
- else
- fail;
- }
- end
-
- #endif /* IconCalling */
- #endif /* ExternalFunctions */
- #endif /* !COMPILER */
-
-
- "char(i) - produce a string consisting of character i."
-
- function{1} char(i)
-
- if !cnv:C_integer(i) then
- runerr(101,i)
- abstract {
- return string
- }
- body {
- if (i < 0 || i > 255) {
- irunerr(205, i);
- errorfail;
- }
- return string(1, &allchars[FromAscii(i) & 0xFF]);
- }
- end
-
-
- "collect(i1,i2) - call garbage collector to ensure i2 bytes in region i1."
- " no longer works."
-
- function{1} collect(region, bytes)
-
- if !def:C_integer(region, (C_integer)0) then
- runerr(101, region)
- if !def:C_integer(bytes, (C_integer)0) then
- runerr(101, bytes)
-
- abstract {
- return null
- }
- body {
- if (bytes < 0) {
- irunerr(205, bytes);
- errorfail;
- }
- if (region < 0 || region > 3) {
- irunerr(205, region);
- errorfail;
- }
- if (collect((int)region,bytes))
- return nulldesc;
- else
- fail;
- }
- end
-
-
- "copy(x) - make a copy of object x."
-
- function{1} copy(x)
- abstract {
- return type(x)
- }
- type_case x of {
- null:
- string:
- cset:
- integer:
- real:
- file:
- procedure:
- co_expression:
- inline {
- /*
- * Copy the null value, integers, long integers, reals, files,
- * csets, procedures, and such by copying the descriptor.
- * Note that for integers, this results in the assignment
- * of a value, for the other types, a pointer is directed to
- * a data block.
- */
- return x;
- }
-
- list:
- inline {
- /*
- * Pass the buck to cplist to copy a list.
- */
- if (cplist(&x, &result, (word)1, BlkLoc(x)->list.size + 1) ==Error)
- runerr(0);
- return result;
- }
- table: {
- body {
- register int i;
- register word slotnum;
- tended union block *src;
- tended union block *dst;
- tended struct b_slots *seg;
- tended struct b_telem *ep, *prev;
- struct b_telem *te;
- /*
- * Copy a Table. First, allocate and copy header and slot blocks.
- */
- src = BlkLoc(x);
- dst = hmake(T_Table, src->table.mask + 1, src->table.size);
- if (dst == NULL)
- runerr(0);
- dst->table.size = src->table.size;
- dst->table.mask = src->table.mask;
- dst->table.defvalue = src->table.defvalue;
- for (i = 0; i < HSegs && src->table.hdir[i] != NULL; i++)
- memcopy((char *)dst->table.hdir[i], (char *)src->table.hdir[i],
- src->table.hdir[i]->blksize);
- /*
- * Work down the chain of element blocks in each bucket
- * and create identical chains in new table.
- */
- for (i = 0; i < HSegs && (seg = dst->table.hdir[i]) != NULL; i++)
- for (slotnum = segsize[i] - 1; slotnum >= 0; slotnum--) {
- prev = NULL;
- for (ep = (struct b_telem *)seg->hslots[slotnum];
- ep != NULL; ep = (struct b_telem *)ep->clink) {
- Protect(te = alctelem(), runerr(0));
- *te = *ep; /* copy table entry */
- if (prev == NULL)
- seg->hslots[slotnum] = (union block *)te;
- else
- prev->clink = (union block *)te;
- te->clink = ep->clink;
- prev = te;
- }
- }
-
- if (TooSparse(dst))
- hshrink(dst);
- return table(dst);
- }
- }
-
- set: {
- body {
- /*
- * Pass the buck to cpset to copy a set.
- */
- if (cpset(&x, &result, BlkLoc(x)->set.size) == Error)
- runerr(0);
- return result;
- }
- }
-
- record: {
- body {
- /*
- * Note, these pointers don't need to be tended, because they are
- * not used until after allocation is complete.
- */
- struct b_record *new_rec;
- tended struct b_record *old_rec;
- dptr d1, d2;
- int i;
-
- /*
- * Allocate space for the new record and copy the old
- * one into it.
- */
- old_rec = (struct b_record *)BlkLoc(x);
- i = old_rec->recdesc->proc.nfields;
-
- /* #%#% param changed ? */
- Protect(new_rec = alcrecd(i,old_rec->recdesc), runerr(0));
- d1 = new_rec->fields;
- d2 = old_rec->fields;
- while (i--)
- *d1++ = *d2++;
- return record(new_rec);
- }
- }
-
- default: body {
- #if Never
- if (Type(x) == T_External) {
- word n;
- tended union block *op, *bp;
-
- /*
- * Duplicate the block. Recover number of data words in block,
- * then allocate new block and copy the data.
- */
- op = BlkLoc(x);
- n = (op->externl.blksize - (sizeof(struct b_external) -
- sizeof(word))) / sizeof(word);
- Protect(bp = (union block *)alcextrnl(n), runerr(0));
- while (n--)
- bp->externl.exdata[n] = op->externl.exdata[n];
- result.dword = D_External;
- BlkLoc(result) = bp;
- return result;
- }
- else
- #endif /* Never */
- runerr(123,x);
- }
- }
- end
-
-
- "display(i,f) - display local variables of i most recent"
- " procedure activations, plus global variables."
- " Output to file f (default &errout)."
-
- #ifdef MultiThread
- function{1} display(i,f,c)
- declare { struct b_coexpr *ce = NULL; }
- #else /* MultiThread */
- function{1} display(i,f)
- #endif /* MultiThread */
-
- if !def:C_integer(i,(C_integer)k_level) then
- runerr(101, i)
-
- if is:null(f) then
- inline {
- f = errout;
- }
- else if !is:file(f) then
- runerr(105, f)
-
- #ifdef MultiThread
- if !is:null(c) then inline {
- if (!is:co_expression(c)) runerr(118,c);
- else if (BlkLoc(c) != BlkLoc(k_current))
- ce = (struct b_coexpr *)BlkLoc(c);
- }
- #endif /* MultiThread */
-
- abstract {
- return null
- }
-
- body {
- FILE *std_f;
- int r;
-
- if (!debug_info)
- runerr(402);
-
- /*
- * Produce error if file cannot be written.
- */
- std_f = BlkLoc(f)->file.fd;
- if ((BlkLoc(f)->file.status & Fs_Write) == 0)
- runerr(213, f);
-
- /*
- * Produce error if i is negative; constrain i to be >= &level.
- */
- if (i < 0) {
- irunerr(205, i);
- errorfail;
- }
- else if (i > k_level)
- i = k_level;
-
- fprintf(std_f,"co-expression_%ld(%ld)\n\n",BlkLoc(k_current)->coexpr.id,
- BlkLoc(k_current)->coexpr.size);
- fflush(std_f);
- #ifdef MultiThread
- if (ce)
- r = xdisp(ce->es_pfp, ce->es_argp, (int)i, std_f);
- else
- #endif /* MultiThread */
- r = xdisp(pfp, argp, (int)i, std_f);
- if (r == Failed)
- runerr(305);
- return nulldesc;
- }
- end
-
-
- "errorclear() - clear error condition."
-
- function{1} errorclear()
- abstract {
- return null
- }
- body {
- k_errornumber = 0;
- k_errortext = "";
- k_errorvalue = nulldesc;
- have_errval = 0;
- return nulldesc;
- }
- end
-
- #if !COMPILER
-
- "function() - generate the names of the functions."
-
- function{*} function()
- abstract {
- return string
- }
- body {
- register int i;
-
- for (i = 0; i<pnsize; i++) {
- if (isalpha(pntab[i].pstrep[0])) /* only suspend function names */
- suspend string(strlen(pntab[i].pstrep), pntab[i].pstrep);
- }
- fail;
- }
- end
- #endif /* !COMPILER */
-
-
- /*
- * the bitwise operators are identical enough to be expansions
- * of a macro.
- */
-
- #begdef bitop(func_name, c_op, operation)
- #func_name "(i,j) - produce bitwise " operation " of i and j."
- function{1} func_name(i,j)
- /*
- * i and j must be integers
- */
- if !cnv:integer(i) then
- runerr(101,i)
- if !cnv:integer(j) then
- runerr(101,j)
-
- abstract {
- return integer
- }
- inline {
- #ifdef LargeInts
- if ((Type(i)==T_Lrgint) || (Type(j)==T_Lrgint)) {
- big_ ## c_op(i,j);
- }
- else
- #endif /* LargeInts */
- return C_integer IntVal(i) c_op IntVal(j);
- }
- end
- #enddef
-
- #define bitand &
- #define bitor |
- #define bitxor ^
- #begdef big_bitand(x,y)
- {
- if (bigand(&x, &y, &result) == Error) /* alcbignum failed */
- runerr(0);
- return result;
- }
- #enddef
- #begdef big_bitor(x,y)
- {
- if (bigor(&x, &y, &result) == Error) /* alcbignum failed */
- runerr(0);
- return result;
- }
- #enddef
- #begdef big_bitxor(x,y)
- {
- if (bigxor(&x, &y, &result) == Error) /* alcbignum failed */
- runerr(0);
- return result;
- }
- #enddef
-
- bitop(iand, bitand, "AND") /* iand(i,j) bitwise "and" of i and j */
- bitop(ior, bitor, "inclusive OR") /* ior(i,j) bitwise "or" of i and j */
- bitop(ixor, bitxor, "exclusive OR") /* ixor(i,j) bitwise "xor" of i and j */
-
-
- "icom(i) - produce bitwise complement (one's complement) of i."
-
- function{1} icom(i)
- /*
- * i must be an integer
- */
- if !cnv:integer(i) then
- runerr(101, i)
-
- abstract {
- return integer
- }
- inline {
- #ifdef LargeInts
- if (Type(i) == T_Lrgint) {
- struct descrip td;
-
- td.dword = D_Integer;
- IntVal(td) = -1;
- if (bigsub(&td, &i, &result) == Error) /* alcbignum failed */
- runerr(0);
- return result;
- }
- else
- #endif /* LargeInts */
- return C_integer ~IntVal(i);
- }
- end
-
-
- "image(x) - return string image of object x."
- /*
- * All the interesting work happens in getimage()
- */
- function{1} image(x)
- abstract {
- return string
- }
- inline {
- register int i;
- if (getimage(&x,&result) == Error)
- runerr(0);
- return result;
- }
- end
-
-
- "ishift(i,j) - produce i shifted j bit positions (left if j<0, right if j>0)."
-
- function{1} ishift(i,j)
-
- if !cnv:integer(i) then
- runerr(101, i)
- if !cnv:integer(j) then
- runerr(101, j)
-
- abstract {
- return integer
- }
- body {
- uword ci; /* shift in 0s, even if negative */
- C_integer cj;
- #ifdef LargeInts
- if (Type(j) == T_Lrgint)
- runerr(101,j);
- if (Type(i) == T_Lrgint || IntVal(j)>0) {
- if (bigshift(&i, &j, &result) == Error) /* alcbignum failed */
- runerr(0);
- return result;
- }
- #endif /* LargeInts */
- ci = (uword)IntVal(i);
- cj = IntVal(j);
- /*
- * Check for a shift of WordSize or greater; return an explicit 0 because
- * this is beyond C's defined behavior. Otherwise shift as requested.
- */
- if (cj <= -WordBits || cj >= WordBits)
- return C_integer 0;
- else if (cj < 0)
- return C_integer ci >> -cj;
- else
- return C_integer ci << cj;
- }
- end
-
-
- "ord(s) - produce integer ordinal (value) of single chracter."
-
- function{1} ord(s)
- if !cnv:tmp_string(s) then
- runerr(103, s)
- abstract {
- return integer
- }
- body {
- if (StrLen(s) != 1)
- runerr(205, s);
- return C_integer ToAscii(*StrLoc(s) & 0xFF);
- }
- end
-
-
- "name(v) - return the name of a variable."
-
- #ifdef MultiThread
- function{1} name(underef v, c)
- declare {
- struct progstate *prog, *savedprog;
- }
- #else /* MultiThread */
- function{1} name(underef v)
- #endif /* MultiThread */
- /*
- * v must be a variable
- */
- if !is:variable(v) then
- runerr(111, v);
-
- abstract {
- return string
- }
-
- body {
- C_integer i;
- if (!debug_info)
- runerr(402);
-
- #ifdef MultiThread
- savedprog = curpstate;
- if (is:null(c)) {
- prog = curpstate;
- }
- else if (is:co_expression(c)) {
- prog = BlkLoc(c)->coexpr.program;
- }
- else {
- runerr(118,c);
- }
-
- ENTERPSTATE(prog);
- #endif /* MultiThread */
- i = get_name(&v, &result); /* return val ? #%#% */
-
- #ifdef MultiThread
- ENTERPSTATE(savedprog);
- #endif /* MultiThread */
-
- if (i == Error)
- runerr(0);
- return result;
- }
- end
-
-
- "runerr(i,x) - produce runtime error i with value x."
-
- function{} runerr(i,x[n])
-
- if !cnv:C_integer(i) then
- runerr(101,i)
- body {
- if (i <= 0) {
- irunerr(205,i);
- errorfail;
- }
- if (n == 0)
- runerr((int)i);
- else
- runerr((int)i, x[0]);
- }
- end
-
-
- "seq(i, j) - generate i, i+j, i+2*j, ... ."
-
- function{1,*} seq(from, by)
-
- if !def:C_integer(from, 1) then
- runerr(101, from)
- if !def:C_integer(by, 1) then
- runerr(101, by)
- abstract {
- return integer
- }
- body {
- word seq_lb, seq_ub;
-
- /*
- * Produce error if by is 0, i.e., an infinite sequence of from's.
- */
- if (by > 0) {
- seq_lb = MinLong + by;
- seq_ub = MaxLong;
- }
- else if (by < 0) {
- seq_lb = MinLong;
- seq_ub = MaxLong + by;
- }
- else if (by == 0) {
- irunerr(211, by);
- errorfail;
-
- }
-
- /*
- * Suspend sequence, stopping when largest or smallest integer
- * is reached.
- */
- do {
- suspend C_integer from;
- from += by;
- }
- while (from >= seq_lb && from <= seq_ub);
-
- #if !COMPILER
- #ifdef TraceBack
- {
- /*
- * Suspending wipes out some things needed by the trace back code to
- * render the offending expression. Restore them.
- */
-
- #include "../h/opdefs.h"
-
- extern dptr xargp;
- extern word xnargs;
-
- #ifndef MultiThread
- extern word lastop; /* last op-code */
- #endif /* MultiThread */
-
- lastop = Op_Invoke;
- xnargs = 2;
- xargp = r_args;
- r_args[0].dword = D_Proc;
- r_args[0].vword.bptr = (union block *)&Bseq;
- }
- #endif /* TraceBack */
- #endif /* COMPILER */
-
- runerr(203);
- }
- end
-
-
- "sort(x,i) - sort list, set, or table x by method i (for tables)"
-
- function{1} sort(t, i)
- type_case t of {
- list: {
- abstract {
- return type(t)
- }
- body {
- register word size;
-
- /*
- * Sort the list by copying it into a new list and then using
- * qsort to sort the descriptors. (That was easy!)
- */
- size = BlkLoc(t)->list.size;
- if (cplist(&t, &result, (word)1, size + 1) == Error)
- runerr(0);
- qsort((char *)BlkLoc(result)->list.listhead->lelem.lslots,
- (int)size, sizeof(struct descrip), (int (*)()) anycmp);
- return result;
- }
- }
-
- set: {
- abstract {
- return new list(store[type(t).set_elem])
- }
- body {
- register dptr d1;
- register word size;
- register int j, k;
- tended struct b_list *lp;
- union block *ep, *bp;
- register struct b_slots *seg;
- /*
- * Create a list the size of the set, copy each element into
- * the list, and then sort the list using qsort as in list
- * sorting and return the sorted list.
- */
- size = BlkLoc(t)->set.size;
-
- Protect(lp = alclist(size), runerr(0));
- Protect(ep = (union block *)alclstb(size,(word)0,size), runerr(0));
- lp->listhead = lp->listtail = ep;
- bp = BlkLoc(t); /* need not be tended if not set until now */
-
- if (size > 0) { /* only need to sort non-empty sets */
- d1 = lp->listhead->lelem.lslots;
- for (j = 0; j < HSegs && (seg = bp->table.hdir[j]) != NULL; j++)
- for (k = segsize[j] - 1; k >= 0; k--)
- for (ep = seg->hslots[k]; ep != NULL; ep= ep->telem.clink)
- *d1++ = ep->selem.setmem;
- qsort((char *)lp->listhead->lelem.lslots,(int)size,
- sizeof(struct descrip), (int (*)())anycmp);
- }
- return list(lp);
- }
- }
-
- table: {
- abstract {
- return new list(new list(store[type(t).key ++ type(t).tbl_elem]) ++
- store[type(t).key ++ type(t).tbl_elem])
- }
- if !def:C_integer(i, 1) then
- runerr(101, i)
- body {
- register dptr d1;
- register word size;
- register int j, k, n;
- tended struct b_table *bp;
- tended struct b_list *lp, *tp;
- tended union block *ep, *ev;
- tended struct b_slots *seg;
-
- switch (i) {
-
- /*
- * Cases 1 and 2 are as in standard Version 5.
- */
- case 1:
- case 2:
- {
- /*
- * The list resulting from the sort will have as many elements
- * as the table has, so get that value and also make a valid
- * list block size out of it.
- */
- size = BlkLoc(t)->table.size;
-
- /*
- * Make sure, now, that there's enough room for all the
- * allocations we're going to need.
- */
- if (!blkreserve((word)(sizeof(struct b_list)
- + sizeof(struct b_lelem) + (size - 1) * sizeof(struct descrip)
- + size * sizeof(struct b_list)
- + size * (sizeof(struct b_lelem) + sizeof(struct descrip)))))
- runerr(0);
- /*
- * Point bp at the table header block of the table to be sorted
- * and point lp at a newly allocated list
- * that will hold the the result of sorting the table.
- */
- bp = (struct b_table *)BlkLoc(t);
- Protect(lp = alclist(size), runerr(0));
- Protect(ep=(union block *)alclstb(size,(word)0,size),runerr(0));
- lp->listtail = lp->listhead = ep;
- /*
- * If the table is empty, there is no need to sort anything.
- */
- if (size <= 0)
- break;
- /*
- * Traverse the element chain for each table bucket. For each
- * element, allocate a two-element list and put the table
- * entry value in the first element and the assigned value in
- * the second element. The two-element list is assigned to
- * the descriptor that d1 points at. When this is done, the
- * list of two-element lists is complete, but unsorted.
- */
-
- n = 0; /* list index */
- for (j = 0; j < HSegs && (seg = bp->hdir[j]) != NULL; j++)
- for (k = segsize[j] - 1; k >= 0; k--)
- for (ep= seg->hslots[k]; ep != NULL; ep= ep->telem.clink){
- Protect(tp = alclist((word)2), runerr(0));
- Protect(ev = (union block *)alclstb((word)2, (word)0, (word)2), runerr(0));
- tp->listhead = tp->listtail = ev;
- tp->listhead->lelem.lslots[0] = ep->telem.tref;
- tp->listhead->lelem.lslots[1] = ep->telem.tval;
- d1 = &lp->listhead->lelem.lslots[n++];
- d1->dword = D_List;
- BlkLoc(*d1) = (union block *)tp;
- }
- /*
- * Sort the resulting two-element list using the sorting
- * function determined by i.
- */
- if (i == 1)
- qsort((char *)lp->listhead->lelem.lslots, (int)size,
- sizeof(struct descrip), (int (*)())trefcmp);
- else
- qsort((char *)lp->listhead->lelem.lslots, (int)size,
- sizeof(struct descrip), (int (*)())tvalcmp);
- break; /* from cases 1 and 2 */
- }
- /*
- * Cases 3 and 4 were introduced in Version 5.10.
- */
- case 3 :
- case 4 :
- {
- /*
- * The list resulting from the sort will have twice as many
- * elements as the table has, so get that value and also make
- * a valid list block size out of it.
- */
- size = BlkLoc(t)->table.size * 2;
-
- /*
- * Point bp at the table header block of the table to be sorted
- * and point lp at a newly allocated list
- * that will hold the the result of sorting the table.
- */
- bp = (struct b_table *)BlkLoc(t);
- Protect(lp = alclist(size), runerr(0));
- Protect(ep = (union block *)alclstb(size,(word)0,size), runerr(0));
- lp->listhead = lp->listtail = ep;
- /*
- * If the table is empty there's no need to sort anything.
- */
- if (size <= 0)
- break;
-
- /*
- * Point d1 at the start of the list elements in the new list
- * element block in preparation for use as an index into the list.
- */
- d1 = lp->listhead->lelem.lslots;
- /*
- * Traverse the element chain for each table bucket. For each
- * table element copy the the entry descriptor and the value
- * descriptor into adjacent descriptors in the lslots array
- * in the list element block.
- * When this is done we now need to sort this list.
- */
-
- for (j = 0; j < HSegs && (seg = bp->hdir[j]) != NULL; j++)
- for (k = segsize[j] - 1; k >= 0; k--)
- for (ep = seg->hslots[k]; ep != NULL; ep = ep->telem.clink) {
- *d1++ = ep->telem.tref;
- *d1++ = ep->telem.tval;
- }
- /*
- * Sort the resulting two-element list using the
- * sorting function determined by i.
- */
- if (i == 3)
- qsort((char *)lp->listhead->lelem.lslots, (int)size / 2,
- (2 * sizeof(struct descrip)), (int (*)())trcmp3);
- else
- qsort((char *)lp->listhead->lelem.lslots, (int)size / 2,
- (2 * sizeof(struct descrip)), (int (*)())tvcmp4);
- break; /* from case 3 or 4 */
- }
-
- default: {
- irunerr(205, i);
- errorfail;
- }
-
- } /* end of switch statement */
-
- /*
- * Make result point at the sorted list.
- */
- return list(lp);
- }
- }
-
- default:
- runerr(115, t);
- }
- end
-
- /*
- * trefcmp(d1,d2) - compare two-element lists on first field.
- */
-
- int trefcmp(d1,d2)
- dptr d1, d2;
- {
-
- #ifdef DeBug
- if (d1->dword != D_List || d2->dword != D_List)
- syserr("trefcmp: internal consistency check fails.");
- #endif /* DeBug */
-
- return (anycmp(&(BlkLoc(*d1)->list.listhead->lelem.lslots[0]),
- &(BlkLoc(*d2)->list.listhead->lelem.lslots[0])));
- }
-
- /*
- * tvalcmp(d1,d2) - compare two-element lists on second field.
- */
-
- int tvalcmp(d1,d2)
- dptr d1, d2;
- {
-
- #ifdef DeBug
- if (d1->dword != D_List || d2->dword != D_List)
- syserr("tvalcmp: internal consistency check fails.");
- #endif /* DeBug */
-
- return (anycmp(&(BlkLoc(*d1)->list.listhead->lelem.lslots[1]),
- &(BlkLoc(*d2)->list.listhead->lelem.lslots[1])));
- }
-
- /*
- * The following two routines are used to compare descriptor pairs in the
- * experimental table sort.
- *
- * trcmp3(dp1,dp2)
- */
-
- int trcmp3(dp1,dp2)
- struct dpair *dp1,*dp2;
- {
- return (anycmp(&((*dp1).dr),&((*dp2).dr)));
- }
- /*
- * tvcmp4(dp1,dp2)
- */
-
- int tvcmp4(dp1,dp2)
- struct dpair *dp1,*dp2;
-
- {
- return (anycmp(&((*dp1).dv),&((*dp2).dv)));
- }
-
-
- "sortf(x,i) - sort list or set x on field i of each member"
-
- function{1} sortf(t, i)
- type_case t of {
- list: {
- abstract {
- return type(t)
- }
- if !def:C_integer(i, 1) then
- runerr (101, i)
- body {
- register word size;
- extern word sort_field;
-
- if (i == 0) {
- irunerr(205, i);
- errorfail;
- }
- /*
- * Sort the list by copying it into a new list and then using
- * qsort to sort the descriptors. (That was easy!)
- */
- size = BlkLoc(t)->list.size;
- if (cplist(&t, &result, (word)1, size + 1) == Error)
- runerr(0);
- sort_field = i;
- qsort((char *)BlkLoc(result)->list.listhead->lelem.lslots,
- (int)size, sizeof(struct descrip), (int (*)()) nthcmp);
- return result;
- }
- }
-
- set: {
- abstract {
- return new list(store[type(t).set_elem])
- }
- if !def:C_integer(i, 1) then
- runerr (101, i)
- body {
- register dptr d1;
- register word size;
- register int j, k;
- tended struct b_list *lp;
- union block *ep, *bp;
- register struct b_slots *seg;
- extern word sort_field;
-
- if (i == 0) {
- irunerr(205, i);
- errorfail;
- }
- /*
- * Create a list the size of the set, copy each element into
- * the list, and then sort the list using qsort as in list
- * sorting and return the sorted list.
- */
- size = BlkLoc(t)->set.size;
-
- Protect(lp = alclist(size), runerr(0));
- Protect(ep = (union block *)alclstb(size,(word)0,size), runerr(0));
- lp->listhead = lp->listtail = ep;
- bp = BlkLoc(t); /* need not be tended if not set until now */
-
- if (size > 0) { /* only need to sort non-empty sets */
- d1 = lp->listhead->lelem.lslots;
- for (j = 0; j < HSegs && (seg = bp->table.hdir[j]) != NULL; j++)
- for (k = segsize[j] - 1; k >= 0; k--)
- for (ep = seg->hslots[k]; ep != NULL; ep= ep->telem.clink)
- *d1++ = ep->selem.setmem;
- sort_field = i;
- qsort((char *)lp->listhead->lelem.lslots,(int)size,
- sizeof(struct descrip), (int (*)())nthcmp);
- }
- return list(lp);
- }
- }
-
- default:
- runerr(125, t); /* list or set expected */
- }
- end
-
- /*
- * nthcmp(d1,d2) - compare two descriptors on their nth fields.
- */
- word sort_field; /* field number, set by sort function */
- static dptr nth Params((dptr d));
-
- int nthcmp(d1,d2)
- dptr d1, d2;
- {
- int t1, t2, rv;
- dptr e1, e2;
-
- t1 = Type(*d1);
- t2 = Type(*d2);
- if (t1 == t2 && (t1 == T_Record || t1 == T_List)) {
- e1 = nth(d1); /* get nth field, or NULL if none such */
- e2 = nth(d2);
- if (e1 == NULL) {
- if (e2 != NULL)
- return -1; /* no-nth-field is < any nth field */
- }
- else if (e2 == NULL)
- return 1; /* any nth field is > no-nth-field */
- else {
- /*
- * Both had an nth field. If they're unequal, that decides.
- */
- rv = anycmp(nth(d1), nth(d2));
- if (rv != 0)
- return rv;
- }
- }
- /*
- * Comparison of nth fields was either impossible or indecisive.
- * Settle it by comparing the descriptors directly.
- */
- return anycmp(d1, d2);
- }
-
- /*
- * nth(d) - return the nth field of d, if any. (sort_field is "n".)
- */
- static dptr nth(d)
- dptr d;
- {
- union block *bp;
- struct b_list *lp;
- word i, j;
- dptr rv;
-
- rv = NULL;
- if (d->dword == D_Record) {
- /*
- * Find the nth field of a record.
- */
- bp = BlkLoc(*d);
- i = cvpos((long)sort_field, (long)(bp->record.recdesc->proc.nfields));
- if (i != CvtFail && i <= bp->record.recdesc->proc.nfields)
- rv = &bp->record.fields[i-1];
- }
- else if (d->dword == D_List) {
- /*
- * Find the nth element of a list.
- */
- lp = (struct b_list *)BlkLoc(*d);
- i = cvpos ((long)sort_field, (long)lp->size);
- if (i != CvtFail && i <= lp->size) {
- /*
- * Locate the correct list-element block.
- */
- bp = lp->listhead;
- j = 1;
- while (i >= j + bp->lelem.nused) {
- j += bp->lelem.nused;
- bp = bp->lelem.listnext;
- }
- /*
- * Locate the desired element.
- */
- i += bp->lelem.first - j;
- if (i >= bp->lelem.nslots)
- i -= bp->lelem.nslots;
- rv = &bp->lelem.lslots[i];
- }
- }
- return rv;
- }
-
-
- "type(x) - return type of x as a string."
-
- function{1} type(x)
- abstract {
- return string
- }
- type_case x of {
- string: inline { return C_string "string"; }
- null: inline { return C_string "null"; }
- integer: inline { return C_string "integer"; }
- real: inline { return C_string "real"; }
- cset: inline { return C_string "cset"; }
- file: inline { return C_string "file"; }
- procedure:inline { return C_string "procedure"; }
- list: inline { return C_string "list"; }
- table: inline { return C_string "table"; }
- set: inline { return C_string "set"; }
- record: inline { return BlkLoc(x)->record.recdesc->proc.recname; }
- co_expression: inline { return C_string "co-expression"; }
- default:
- inline {
- #if !COMPILER
- if (!Qual(x) && (Type(x)==T_External)) {
- return C_string "external";
- }
- else
- #endif /* !COMPILER */
- runerr(123,x);
- }
- }
- end
-
-
- "variable(s) - find the variable with name s and return a"
- " variable descriptor which points to its value."
-
- #ifdef MultiThread
- function{0,1} variable(s,c)
- #else /* MultiThread */
- function{0,1} variable(s)
- #endif /* MultiThread */
-
- if !cnv:C_string(s) then
- runerr(103, s)
- abstract {
- return variable
- }
-
- body {
- register dptr dp;
- register dptr np;
- register int i;
- struct b_proc *bp;
- #ifdef MultiThread
- struct progstate *prog, *savedprog;
-
- savedprog = curpstate;
- if (is:null(c)) {
- prog = curpstate;
- }
- else if (is:co_expression(c)) {
- prog = BlkLoc(c)->coexpr.program;
- }
- else {
- runerr(118,c);
- }
-
- ENTERPSTATE(prog);
- #endif /* MultiThread */
-
- i = getvar(s,&result);
-
- #ifdef MultiThread
- ENTERPSTATE(savedprog);
- #endif /* MultiThread */
-
- if (i == Succeeded)
- return result;
- else
- fail;
- }
- end
-
- #ifdef MultiThread
- #include "../h/opdefs.h"
-
- "load(s,arglist,input,output,error,eventmask,opmask) - load an icode file"
- " corresponding to string s as a co-expression."
-
- function{1} load(s,arglist,infile,outfile,errfile,eventmask,opmask)
- declare {
- tended char *loadstring;
- }
- if !cnv:C_string(s,loadstring) then
- runerr(103,s)
- abstract {
- return co_expression
- }
- body {
- word *stack;
- struct progstate *pstate;
- char sbuf1[MaxCvtLen], sbuf2[MaxCvtLen];
- register struct b_coexpr *sblkp;
- register struct b_refresh *rblkp;
- struct ef_marker *newefp;
- register dptr dp, ndp, dsp;
- register word *newsp, *savedsp;
- int na, nl, i, j, num_fileargs = 0;
- FILE *theInput = NULL, *theOutput = NULL, *theError = NULL;
- struct b_proc *cproc;
- dptr mask = NULL, omask = NULL;
-
- /*
- * Yeah, OK, I freely admit this isn't portable yet. It isn't hard
- * to 16-ify, so I haven't bothered.
- */
- static int lterm[] = { Op_Cofail, Op_Agoto, 0 };
- static int pstart[] =
-
- #ifdef EventMon
- { Op_SymEvents, Op_Invoke, 1, Op_Coret, Op_Cofail, Op_Agoto, 0 };
- #else /* EventMon */
- { Op_Invoke, 1, Op_Coret, Op_Cofail, Op_Agoto, 0 };
- #endif /* EventMon */
-
- #ifdef EventMon
- lterm[2] = pstart[6] = (int)lterm;
- #else /* EventMon */
- lterm[2] = pstart[5] = (int)lterm;
- #endif /* EventMon */
-
- /*
- * arglist must be a list
- */
- if (!is:null(arglist) && !is:list(arglist))
- runerr(108,arglist);
-
- /*
- * input, output, and error must be files
- */
- if (is:null(infile))
- theInput = curpstate->input;
- else {
- if (!is:file(input))
- runerr(105,input);
- else theInput = BlkLoc(infile)->file.fd;
- }
- if (is:null(outfile))
- theOutput = curpstate->output;
- else {
- if (!is:file(outfile))
- runerr(105,outfile);
- else theOutput = BlkLoc(outfile)->file.fd;
- }
- if (is:null(errfile))
- theError = curpstate->errout;
- else {
- if (!is:file(errfile))
- runerr(105,errfile);
- else theError = BlkLoc(errfile)->file.fd;
- }
-
- /*
- * eventmask, and opmask must be csets
- */
- if (!is:null(eventmask)) {
- if (!is:cset(eventmask))
- runerr(104,eventmask);
- else mask = &eventmask;
- }
- if (!is:null(opmask)) {
- if (!is:cset(opmask))
- runerr(104,opmask);
- else mask = &opmask;
- }
-
- stack =
- (word *)(sblkp = loadicode(loadstring,theInput,theOutput,theError));
- if(!stack) {
- fprintf(stderr,"load/loadicode fails\n");
- c_exit(ErrorExit);
- }
- pstate = sblkp->program;
- pstate->parent = curpstate;
- pstate->parentdesc = k_main;
- if (mask) pstate->eventmask = *mask;
- if (omask) pstate->opcodemask = *omask;
-
- savedsp = sp;
- sp = stack + Wsizeof(struct b_coexpr)
- + Wsizeof(struct progstate) + pstate->hsize/WordSize;
- if (pstate->hsize % WordSize) sp++;
-
- #ifdef UpStack
- sblkp->cstate[0] =
- ((word)((char *)sblkp + (mstksize - (sizeof(*sblkp)+sizeof(struct progstate)+pstate->hsize))/2)
- &~((word)WordSize*StackAlign-1));
- #else /* UpStack */
- sblkp->cstate[0] =
- ((word)((char *)sblkp + mstksize - WordSize + sizeof(struct progstate) + pstate->hsize)
- &~((word)WordSize*StackAlign-1));
- #endif /* UpStack */
-
- #ifdef CoProcesses
- sblkp->cstate[1] = 0;
- #endif /* CoProcesses */
-
- sblkp->es_argp = NULL;
- pstate->Mainhead->freshblk = nulldesc;/* &main has no refresh block. */
- /* This really is a bug. */
- /*
- * Set up expression frame marker to contain execution of the
- * main procedure. If failure occurs in this context, control
- * is transferred to lterm, the address of an { Op_Coret, Op_Efail}.
- */
- newefp = (struct ef_marker *)(sp);
- newefp->ef_failure.op = &(lterm[0]);
-
- newefp->ef_gfp = 0;
- newefp->ef_efp = 0;
- newefp->ef_ilevel = ilevel/*1*/;
- sp += Wsizeof(*newefp) - 1;
-
- /*
- * The first global variable holds the value of "main". If it
- * is not of type procedure, this is noted as run-time error 117.
- * Otherwise, this value is pushed on the stack.
- */
- if (pstate->Globals[0].dword != D_Proc)
- fatalerr(117, NULL);
-
- PushDesc(pstate->Globals[0]);
-
- /*
- * Create a list from arguments using Ollist and push a descriptor
- * onto new stack. Then create procedure frame on new stack. Push
- * two new null descriptors, and set sblkp->es_sp when all finished.
- */
- if (!is:null(arglist)) {
- PushDesc(arglist);
- }
- else {
- PushNull;
- {
- dptr tmpargp = (dptr) (sp - 1);
- Ollist(0, tmpargp);
- sp = (word *)tmpargp + 1;
- }
- }
- sblkp->es_sp = (word *)sp;
- sblkp->es_ipc.opnd = pstart;
-
- result.dword = D_Coexpr;
- BlkLoc(result) = (union block *)sblkp;
- sp = savedsp;
- return result;
- }
- end
-
-
- "program(ce) - given a ce, return &main for that ce"
-
- function{1} program(ce)
- if is:null(ce) then inline { ce = k_current; }
- else if !is:co_expression(ce) then runerr(118,ce)
- abstract {
- return co_expression
- }
- body {
- result.dword = D_Coexpr;
- BlkLoc(result) =
- (union block *)(((struct b_coexpr *)BlkLoc(ce))->program->Mainhead);
- return result;
- }
- end
-
-
- "eventmask(ce,cs) - given a ce, get or set that program's event mask"
-
- function{1} eventmask(ce,cs)
- if !is:co_expression(ce) then runerr(118,ce)
-
- if is:null(cs) then {
- abstract {
- return cset++null
- }
- body {
- result = BlkLoc(ce)->coexpr.program->eventmask;
- return result;
- }
- }
- else if !cnv:cset(cs) then runerr(104,cs)
- else {
- abstract {
- return cset
- }
- body {
- ((struct b_coexpr *)BlkLoc(ce))->program->eventmask = cs;
- return cs;
- }
- }
- end
-
-
- "fieldnames(r) - generate the fieldnames of record r"
-
- function{*} fieldnames(r)
- if !is:record(r) then runerr(107,r)
- body {
- int i;
- for(i=0;i<BlkLoc(r)->record.recdesc->proc.nfields;i++) {
- suspend BlkLoc(r)->record.recdesc->proc.lnames[i];
- }
- fail;
- }
- end
-
-
-
- "globalnames(ce) - produce the names of identifiers global to ce"
-
- function{*} globalnames(ce)
- declare {
- struct progstate *ps;
- }
- abstract {
- return string
- }
- if is:null(ce) then inline { ps = curpstate; }
- else if is:co_expression(ce) then
- inline { ps = BlkLoc(ce)->coexpr.program; }
- else runerr(118,ce)
- body {
- struct descrip *dp;
- for (dp = ps->Gnames; dp != ps->Egnames; dp++) {
- suspend *dp;
- }
- fail;
- }
- end
-
- "localnames(ce) - produce the names of local variables"
- " in the current procedure activation in ce"
- function{*} localnames(ce)
- declare {
- tended struct descrip d;
- }
- abstract {
- return string
- }
- if is:null(ce) then inline {
- d = k_current;
- BlkLoc(k_current)->coexpr.es_pfp = pfp; /* sync w/ current value */
- }
- else if is:co_expression(ce) then
- inline { d = ce; }
- else runerr(118,ce)
- body {
- int i;
- dptr arg;
- struct b_proc *cproc;
- struct pf_marker *thePfp = BlkLoc(d)->coexpr.es_pfp;
- arg = &((dptr)thePfp)[-(thePfp->pf_nargs) - 1];
- cproc = (struct b_proc *)BlkLoc(arg[0]);
- for(i=0; i<cproc->ndynam;i++) {
- result = cproc->lnames[i+cproc->nparam];
- suspend result;
- }
- fail;
- }
- end
-
-
- "opmask(ce,cs) - given a ce, set that program's opcode mask"
-
- function{1} opmask(ce,cs)
- if !is:co_expression(ce) then runerr(118,ce)
-
- if is:null(cs) then {
- abstract {
- return cset++null
- }
- body {
- result = BlkLoc(ce)->coexpr.program->opcodemask;
- return result;
- }
- }
- else if !cnv:cset(cs) then runerr(104,cs)
- else {
- abstract {
- return cset
- }
- body {
- ((struct b_coexpr *)BlkLoc(ce))->program->opcodemask = cs;
- return cs;
- }
- }
- end
-
- "staticnames(ce) - produce the names of static variables"
- " in the current procedure activation in ce"
-
- function{*} staticnames(ce)
- declare {
- tended struct descrip d;
- }
- abstract {
- return string
- }
- if is:null(ce) then inline {
- d = k_current;
- BlkLoc(k_current)->coexpr.es_pfp = pfp; /* sync w/ current value */
- }
- else if is:co_expression(ce) then
- inline { d = ce; }
- else runerr(118,ce)
- body {
- int i;
- dptr arg;
- struct b_proc *cproc;
- struct pf_marker *thePfp = BlkLoc(d)->coexpr.es_pfp;
- arg = &((dptr)thePfp)[-(thePfp->pf_nargs) - 1];
- cproc = (struct b_proc *)BlkLoc(arg[0]);
- for(i=0; i<cproc->nstatic;i++) {
- result = cproc->lnames[i+cproc->nparam+cproc->ndynam];
- suspend result;
- }
- fail;
- }
- end
-
- "paramnames(ce) - produce the names of the parameters"
- " in the current procedure activation in ce"
-
- function{1,*} paramnames(ce)
- declare {
- tended struct descrip d;
- }
- abstract {
- return string
- }
- if is:null(ce) then inline {
- d = k_main;
- BlkLoc(k_main)->coexpr.es_pfp = pfp; /* sync w/ current value */
- }
- else if is:co_expression(ce) then
- inline { d = ce; }
- else runerr(118,ce)
- body {
- int i;
- dptr arg;
- struct b_proc *cproc;
- struct pf_marker *thePfp = BlkLoc(d)->coexpr.es_pfp;
- arg = &((dptr)thePfp)[-(thePfp->pf_nargs) - 1];
- cproc = (struct b_proc *)BlkLoc(arg[0]);
- for(i=0; i<cproc->nparam;i++) {
- result = cproc->lnames[i];
- suspend result;
- }
- fail;
- }
- end
- #endif /* MultiThread */
-